import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import os
from matplotlib.colors import LinearSegmentedColormap


class EnhancedBarVisualizer:
    def __init__(self, df, columns, label_mapping, title_mapping=None, color_palette=None, output_dir='分析', prefix=''):
        self.df = df.copy()
        self.columns = columns if isinstance(columns, list) else [columns]
        self.label_mapping = label_mapping
        self.title_mapping = title_mapping or {}
        self.output_dir = output_dir
        self.prefix = prefix

        self.color_palette = color_palette or [
            '#2E86C1', '#3498DB', '#5DADE2', '#85C1E9', '#AED6F1'
        ]
        self._prepare_data()

    def _prepare_data(self):
        self.df = self.df[self.columns].apply(pd.to_numeric, errors='coerce')

    def _configure_styles(self):
        plt.style.use('seaborn-whitegrid')
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.rcParams['axes.unicode_minus'] = False

    def _create_gradient_colors(self):
        return LinearSegmentedColormap.from_list(
            'custom', self.color_palette, N=len(self.columns)
        )(np.linspace(0, 1, len(self.columns)))

    def _generate_annotations(self, bars, ax):
        for bar in bars:
            height = bar.get_height()
            ax.annotate(f'{height:.1f}',
                        xy=(bar.get_x() + bar.get_width() / 2, height),
                        xytext=(0, 3),
                        textcoords="offset points",
                        ha='center', va='bottom')

    def _get_save_path(self, filename):
        os.makedirs(self.output_dir, exist_ok=True)
        return os.path.join(self.output_dir, filename)

    def visualize(self):
        self._configure_styles()
        summary_data = self.df[self.columns].sum()

        labels = [self.label_mapping.get(col, col) for col in summary_data.index]
        summary_data.index = labels

        fig, ax = plt.subplots(figsize=(12, 6))
        bars = ax.bar(
            labels, summary_data.values,
            color=self._create_gradient_colors(),
            edgecolor='#34495E',
            linewidth=0.8,
            width=0.75
        )

        # 修改坐标轴标签和字体设置
        ax.set_title(f"{self.title_mapping.get('_'.join(self.columns), '数据分布')}\n",
                     loc='left', pad=20, fontsize=16)  # 可选标题字号调整
        ax.set_xlabel("分析维度", labelpad=15, fontsize=14)
        ax.set_ylabel("数值汇总", labelpad=15, fontsize=14)

        # 设置刻度标签大小
        plt.xticks(rotation=45, ha='right', rotation_mode='anchor')
        ax.tick_params(axis='x', labelsize=12)
        ax.tick_params(axis='y', labelsize=12)

        ax.grid(axis='y', linestyle='--', alpha=0.7, color='#D5D8DC')
        self._generate_annotations(bars, ax)
        for spine in ax.spines.values():
            spine.set_visible(False)

        plt.tight_layout()
        save_path = self._get_save_path(f"{self.prefix}.png")
        plt.savefig(save_path, bbox_inches='tight', pad_inches=0.3)
        plt.close()

    def visualize_combo(self):
        self._configure_styles()
        summary_data = self.df[self.columns].sum().sort_values(ascending=False)
        labels = [self.label_mapping.get(col, col) for col in summary_data.index]

        cumulative = summary_data.cumsum()
        cumulative_percent = cumulative / cumulative.max() * 100

        fig, ax1 = plt.subplots(figsize=(14, 7))
        bars = ax1.bar(
            labels, summary_data.values,
            color=self.color_palette[0],
            alpha=0.7,
            width=0.6
        )

        # 主坐标轴设置
        ax1.set_xlabel("分析维度", labelpad=15, fontsize=14)
        ax1.set_ylabel("数量", labelpad=15, fontsize=14)
        ax1.tick_params(axis='x', labelsize=12)
        ax1.tick_params(axis='y', labelsize=12)

        # 次坐标轴设置
        ax2 = ax1.twinx()
        line, = ax2.plot(
            labels, cumulative_percent.values,
            color='#FF8000',
            marker='o',
            markersize=8,
            linewidth=2.5,
            linestyle='--'
        )
        ax2.set_ylabel("累计百分比 (%)", labelpad=15, fontsize=14)
        ax2.tick_params(axis='y', labelsize=12)
        ax2.set_ylim(0, 110)

        # 标题和图例
        ax1.set_title(f"{self.title_mapping.get('_'.join(self.columns), '数据分布')} - 组合分析\n",
                      loc='left', pad=20, fontsize=16)  # 可选标题字号调整
        ax1.legend([bars, line], ['数量', '累计百分比'],
                   loc='upper right', bbox_to_anchor=(1.1, 1.2),
                   frameon=False,fontsize=14)

        # 标注和样式
        self._generate_annotations(bars, ax1)
        for x, y in zip(labels, cumulative_percent):
            ax2.annotate(f'{y:.1f}%',
                         xy=(x, y),
                         xytext=(0, 10),
                         textcoords="offset points",
                         ha='center', va='bottom',
                         color='#FF8000',
                         fontweight='bold')

        plt.xticks(rotation=45, ha='right', rotation_mode='anchor')
        plt.grid(axis='y', alpha=0.3)
        plt.tight_layout()
        save_path = self._get_save_path(f"{self.prefix}_combo.png")
        plt.savefig(save_path, bbox_inches='tight', pad_inches=0.3)
        plt.close()

# 定义标签映射字典
LABEL_MAPPINGS = {
    'S': {
        'S1': '工作日简餐',
        'S2': '周末家庭聚餐',
        'S3': '应急储备',
        'S4': '健身减肥',
        'S5': '节日送礼',
        'S6': '加班熬夜',
        'S7': '其他场景'
    },
    'C': {
        'C1': '超市/便利店',
        'C2': '生鲜电商',
        'C3': '直播带货',
        'C4': '社区团购',
        'C5': '品牌官网/小程序',
        'C6': '线下体验店',
        'C7': '其他渠道'
    },
    'P': {
        'P1': '家常菜',
        'P2': '主食类',
        'P3': '汤羹类',
        'P4': '地方特色',
        'P5': '健康轻食',
        'P6': '网红爆款',
        'P7': '儿童营养餐',
        'P8': '其他类型'
    },
    'A': {
        'A1': '提升口感还原度',
        'A2': '增加菜品多样性',
        'A3': '优化包装',
        'A4': '缩短加热时间',
        'A5': '降低价格',
        'A6': '加强食品安全标识',
        'A7': '融入地方文化特色',
        'A8': '提供烹饪仪式感',
        'A9': '其他改进'
    },
    'Q': {
        'Q1': '配送问题',
        'Q2': '包装破损',
        'Q3': '分量缩水',
        'Q4': '图文不符',
        'Q5': '无问题',
        'Q6': '其他问题'
    }
}

if __name__ == '__main__':
    # 初始化输出目录
    output_folder = '分析'
    os.makedirs(output_folder, exist_ok=True)

    df = pd.read_excel('clear_maded_food.xlsx', sheet_name='预制表格')
    analysis_groups = [
        ('S', ['S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7']),
        ('C', ['C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7']),
        ('P', ['P1', 'P2', 'P3', 'P4', 'P5', 'P6', 'P7', 'P8']),
        ('A', ['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9']),
        ('Q', ['Q1', 'Q2', 'Q3', 'Q4', 'Q5', 'Q6'])
    ]
    buy_yes_df = df[df['buy'] == '是']

    for group_key, columns in analysis_groups:
        visualizer = EnhancedBarVisualizer(
            df=buy_yes_df,
            columns=columns,
            label_mapping=LABEL_MAPPINGS[group_key],
            color_palette=['#1A5276', '#2874A6', '#2E86C1', '#5499C7', '#85C1E9'],
            output_dir=output_folder,
            prefix=f'buy_yes_{group_key}'
        )
        visualizer.visualize()
        visualizer.visualize_combo()

    print(f"分析结果已保存至：{os.path.abspath(output_folder)}")